import pandas as pd
from sklearn.feature_extraction import DictVectorizer
from sklearn.tree import DecisionTreeClassifier
import numpy as np
from sklearn.model_selection import cross_val_score

# 数据加载
train_data = pd.read_csv('train.csv')
test_data = pd.read_csv('test.csv')
# 数据探索
print(train_data.info())
print('-'*30)
print(train_data.describe())
print('-'*30)
print(train_data.describe(include=['O']))
print('-'*30)
print(train_data.head())
print('-'*30)
print(train_data.tail())
# 数据清洗
# 使用平均年龄来填充年龄中的 nan 值
train_data['Age'].fillna(train_data['Age'].mean(), inplace=True)
test_data['Age'].fillna(test_data['Age'].mean(),inplace=True)
# 使用票价的均值填充票价中的 nan 值
train_data['Fare'].fillna(train_data['Fare'].mean(), inplace=True)
test_data['Fare'].fillna(test_data['Fare'].mean(),inplace=True)
print(train_data['Embarked'].value_counts())

# 使用登录最多的港口来填充登录港口的 nan 值
train_data['Embarked'].fillna('S', inplace=True)
test_data['Embarked'].fillna('S',inplace=True)

# 特征选择
features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
train_features = train_data[features]
train_labels = train_data['Survived']

# test_features已经从test_data中提取出来了
test_features = test_data[features]

dvec=DictVectorizer(sparse=False)

# dvec.fit_transform 用于训练和转换数据，将数据转换为字典形式并进行特征提取和向量化处理。这个方法会返回处理后的特征矩阵。
# dvec.transform 方法只进行数据转换，即将新数据转换为字典形式并进行特征提取和向量化处理，这个方法只返回转换后的特征矩阵，不进行训练

train_features=dvec.fit_transform(train_features.to_dict(orient='records'))
print(dvec.feature_names_)

# 构造 ID3 决策树
clf = DecisionTreeClassifier(criterion='entropy')
# 决策树训练
clf.fit(train_features, train_labels)

# 将其转换为NumPy数组或字典格式
# dvec.transform是将数据集进行特征向量化的方法，它将数据集中的非数值型特征转换为数值型特征，以便于分类器等机器学习算法的处理
test_features=dvec.transform(test_features.to_dict(orient='records'))
# 决策树预测
pred_labels = clf.predict(test_features)


# 得到决策树准确率
acc_decision_tree = round(clf.score(train_features, train_labels), 6)
print(u'score 准确率为 %.4lf' % acc_decision_tree)


# 使用K折交叉验证  统计决策树准确率
# 使用score函数对训练集的准确率进行统计，正确率会接近于100%（如上结果为98.2%），但是这并不能代表决策树分类器的准确率。
# 因为我们没有测试集的实际结果，所以无法用测试集的预测结果与实际结果做对比。
# 而使用K折交叉验证可以更好地评估模型的性能，因为它可以使用所有的数据来进行训练和测试，从而更好地反映模型的性能。
print(u'cross_val_score准确率为 %.4lf' % np.mean(cross_val_score(clf, train_features, train_labels, cv=10)))